Skip to content

feat(pkg): publish an installable package on every release - #12

Merged
phmatray merged 4 commits into
mainfrom
feat/16-package-on-release
Sep 4, 2026
Merged

feat(pkg): publish an installable package on every release#12
phmatray merged 4 commits into
mainfrom
feat/16-package-on-release

Conversation

@phmatray

@phmatray phmatray commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Implements macarchy/macarchy-install#16 (part of macarchy/macarchy-install#14).

Cross-repo: the tracking issue lives in macarchy-install because it spans the org, so this PR cannot auto-close it. It is ticked and closed by hand on merge.

Why

A release here carries zero assets — only the source zip GitHub attaches to any tag. "Install macarchy-touchbar" means clone the repo and run install.sh. This makes a release something you can install:

pacman -U macarchy-touchbar-0.4.1-1-any.pkg.tar.zst

install.sh is untouched. The package is an additional channel, not a replacement.

The bug that had to be fixed first

The PKGBUILD could not have worked as a pure packaging change. daemon.py:23 and draw.py:24:

ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
specs = discover(os.path.join(ROOT, "modules"), …)

ROOT is the parent of the python package — the repo root in a checkout, and /usr/lib/python3.14/site-packages/ once installed. A package built without fixing that installs cleanly and then comes up with an empty bar.

paths.data_root() now resolves $MACARCHY_TOUCHBAR_DATA/usr/share/macarchy-touchbar → the checkout root. The env var is honoured even when it points nowhere: someone who sets it meant it, and a silent fallback hides the typo until the bar is empty.

Two things the real build taught

Both were found by building the package on the target hardware and reading tar -tf, not by the tests.

The font is unpinned today. install.sh:27 curls it from master. Fetching it from the commit this PKGBUILD pins gives a different file from the copy installed on 2 Sep — 15,107,604 bytes against 15,090,976. Two machines set up a week apart do not have the same font. Now pinned to a commit, with a real checksum.

|| true shipped a broken package. The .codepoints file is gitignored, so it is absent from the release tarball — and draw.py:57 opens it. The first PKGBUILD had || true on that line and produced a package with an empty fonts/ directory and a bar with no icons. It is a third pinned source now, and a test asserts no || true survives on a non-comment line.

Verification

Built for real on aarch64 Asahi with makepkg 7.1.0 from the v0.4.0 tarball:

5.3M  macarchy-touchbar-0.4.0-1-any.pkg.tar.xz

usr/bin/macarchy-touchbar
usr/lib/{modules-load.d,udev/rules.d,systemd/user}/…
usr/lib/python3.14/site-packages/macarchy_touchbar/…
usr/share/macarchy-touchbar/{modules,config}/…
usr/share/macarchy-touchbar/fonts/MaterialSymbolsRounded.codepoints
usr/share/fonts/TTF/MaterialSymbolsRounded.ttf

The daemon still starts from a checkout — verified headless, all five modules plus the Jarvis plugin loaded.

Suite: 156 passed, 2 skipped. tests/test_pkgbuild.py keeps the two install channels from drifting and records the asymmetry that caused the issue: macarchy_touchbar/, modules/ and config/ are not copied by install.sh, because the daemon reads them in place.

pkgver carries release-please's x-release-please-version marker and the config lists PKGBUILD under extra-files, so the version is maintained rather than hand-bumped — pinned by a test, because without it a release ships a package numbered for the previous tag.

🤖 Generated with Claude Code

https://claude.ai/code/session_01SYBhT1xfp3MQ1w3687F4Mp

phmatray and others added 4 commits September 5, 2026 01:17
modules/, config/layouts.toml and fonts/*.codepoints were found at
os.path.dirname(os.path.dirname(__file__)) -- one directory above the python
package. That is the repo root in a git checkout and nothing useful anywhere
else: installed as a system package, macarchy_touchbar/ sits in site-packages/,
so the daemon would look for modules/ in /usr/lib/pythonX.Y/site-packages/ and
come up with an empty bar. macarchy-install#16 found this before the PKGBUILD
was written, which is the only reason it is not a shipped artifact that installs
cleanly and then fails to start.

paths.data_root() resolves three candidates in order: $MACARCHY_TOUCHBAR_DATA,
then /usr/share/macarchy-touchbar if it really holds modules/, then the checkout
root. The env var is honoured even when it points nowhere -- someone who sets it
meant it, and a silent fallback would hide the typo until the bar came up empty.

The checkout fallback is the old behaviour unchanged, so ./install.sh keeps
working exactly as before; verified by starting the daemon headless from a
checkout and watching all five modules plus the Jarvis plugin load.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SYBhT1xfp3MQ1w3687F4Mp
Installs system-wide what ./install.sh installs into $HOME: the CLI, the python
package, modules/ and config/ under /usr/share, the udev rule, the modules-load
drop-in and the user unit. Built for real on the target hardware from the v0.4.0
tarball -- 5.3 MB, and every path verified with `tar -tf` rather than assumed.

Two things the real build taught, neither of which the tests saw first:

The Material Symbols font is fetched by install.sh:27 from `master`, unpinned.
Downloading it today from the commit this PKGBUILD pins gives a DIFFERENT file
from the copy installed on 2 Sep -- 15,107,604 bytes against 15,090,976. Two
machines set up a week apart do not have the same font. The commit is pinned and
both checksums are real.

The .codepoints file is gitignored, so it is absent from the release tarball --
and draw.py:57 opens it. The first version of this PKGBUILD had `|| true` on that
install line, which silently produced a package with an empty fonts/ directory
and a bar with no icons. It is now a third pinned source and the `|| true` is
gone; a test asserts no `|| true` survives on a non-comment line.

pkgver carries release-please's `x-release-please-version` marker and the config
lists PKGBUILD under extra-files, so the version is maintained rather than
hand-bumped. A test pins both -- without them a release ships a package built
from the previous tag's number, silently.

tests/test_pkgbuild.py keeps the two install channels from drifting: everything
install.sh copies must appear in package(). It also records the asymmetry that
caused this issue -- macarchy_touchbar/, modules/ and config/ are NOT copied by
install.sh, because the daemon reads them in place from the checkout.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SYBhT1xfp3MQ1w3687F4Mp
Builds the PKGBUILD in archlinux:base-devel when a release is published and
uploads the result onto that release, so `pacman -U` becomes a real way to
install this. macarchy-install#16.

Release-only on purpose: the PKGBUILD's source is the release tarball, which
does not exist until the tag does, so a push or pull_request trigger could only
ever fail. workflow_dispatch takes a tag for re-running a job that failed.

The upload globs `*.pkg.tar.*` rather than naming an extension -- PKGEXT is .zst
in this container and .xz on the maintainer's machine, and hardcoding either
uploads nothing on the other. --clobber so a re-run replaces the asset.

makepkg runs as a throwaway non-root user because it refuses to run as root, and
with --nodeps because `depends` is a runtime contract for the target machine,
not a build requirement for the container.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SYBhT1xfp3MQ1w3687F4Mp
Eleven findings, and the first would have made the whole feature a decoration.

CRITICAL -- `release: [published]` would never have fired. release-please creates
the Release with the default GITHUB_TOKEN, and GitHub raises no workflow run from
a GITHUB_TOKEN event. Every release would have published with no package and no
failed run anywhere to notice. This repo has already paid for that lesson once,
which is why the Tauri build was folded into release-please.yml; package.yml is
deleted and the job now hangs off release-please's own `release_created` output.

HIGH -- the shipped unit says ExecStart=%h/.local/bin/…, written for install.sh's
symlink. A package writes nothing into $HOME, so it would have given 203/EXEC,
ten restarts to StartLimitBurst and an OnFailure toast, from a package that
installed perfectly. package() now rewrites it to /usr/bin and greps to confirm.

HIGH -- `gh` lives on the runner, not inside the container; the upload would have
died with command not found. github-cli added, and `pacman -Sy` became -Syu so a
partial upgrade cannot link the fresh python against a glibc the image lacks.

HIGH -- arch=('any') with a site-packages path derived from the BUILDING
interpreter bakes that container's python version into the artifact; Asahi's
python trails it, and the target gets ImportError while depends=('python') claims
otherwise. Fixed by co-locating: macarchy_touchbar/ now installs NEXT TO modules/
and config/ under /usr/share/macarchy-touchbar, so "one directory above the
package" resolves in both layouts and there is one rule instead of two. That also
dissolves the finding that PACKAGED outranked the checkout and let an installed
package hijack every checkout on the machine -- there is no PACKAGED any more.

MEDIUM -- pacman cannot do install.sh's non-file half (video group, uinput,
masking tiny-dfr), so a package-only install left a blank bar with no explanation.
macarchy-touchbar.install now prints those steps, restarts on upgrade and hands
the panel back to tiny-dfr on removal.

MEDIUM -- workflow_dispatch checked out the default branch, so re-running for an
older tag built main's PKGBUILD and clobbered that package onto the old release.
It takes an explicit ref now, and the upload refuses a package whose filename
does not carry the target tag.

LOW -- the drift test matched the whole file including comments, which name every
artefact, so deleting an install line still passed: it reads comment-stripped code
now. CODEPOINTS froze data_root() at import while daemon.py called it per use;
it is codepoints_path() (renamed to avoid colliding with the existing _codepoints
cache). The checkout test never patched PACKAGED and would have started asserting
against packaged data once this shipped.

Rebuilt and re-verified rather than assumed: the unit reads
ExecStart=/usr/bin/macarchy-touchbar, nothing lands in site-packages, and the
launcher resolves from a checkout, from a simulated /usr prefix via the env var,
and fails with the list of places it looked when the tree is genuinely absent.

Suite: 159 passed, 2 skipped.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SYBhT1xfp3MQ1w3687F4Mp
@phmatray
phmatray merged commit 8e0615f into main Sep 4, 2026
1 check passed
@phmatray
phmatray deleted the feat/16-package-on-release branch September 4, 2026 23:32
phmatray added a commit that referenced this pull request Sep 4, 2026
Restores the entry release-please dropped. The squash body of #12 opens with
GitHub's default `* feat: …` bullet list, which release-please parses as nested
conventional commits; the top-level `feat(pkg):` was lost, so it proposed 0.4.1
with a Bug Fixes section and no mention of the packaging at all.

The work is already on main (8e0615f, 62dd9af): a PKGBUILD that mirrors
install.sh, a packaging job folded into release-please.yml because a
`release: published` trigger never fires on a GITHUB_TOKEN-created release, the
unit repointed off $HOME, and a scriptlet for the half of install.sh pacman
cannot do.

Lesson for the next squash: write the body, do not accept GitHub's bullets.

Release-As: 0.5.0

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SYBhT1xfp3MQ1w3687F4Mp
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant